import { createWxSDK } from '../../sdk/weixin';
import { createSmsSDK } from '../../sdk/sms';
import { SMS_TEMPLATE } from '../../sdk/sms/templates';
import { RedisService } from '../../sdk/redis/RedisService';
import config from '../../config';
import { Like, Repository } from 'typeorm';
import { AppDataSource } from '../../config/database';
import { User, UserStatus, Gender } from '../../entities/User';
import jwt from 'jsonwebtoken';
import { Dictionary } from '../../entities/Dictionary';

// 定义注册参数接口
export interface RegisterParams {
  name: string;
  gender: Gender;
  birthday: string;
  idCard: string;
  mobile: string;
  address?: string;
  permanentAddress?: string;
  avatar?: string;
  nickname?: string;
  verifyCode: string;
  openId: string;
  idCardFrontPhoto?: string;
}

// 定义组织信息接口
export interface OrgInfo {
  id: string;
  orgName: string;
  nature: number;
  status: number;
}

// 定义角色接口
export interface Role {
  id: number;
  roleId: string;
  roleName: string;
  org?: {
    id: string;
    orgName: string;
  };
}

export class MpWeixinService {
  private wxSDK;
  private smsSDK;
  private redis;
  private readonly VERIFY_CODE_PREFIX = 'verify_code:';
  private readonly SEND_COUNT_PREFIX = 'sms_count:';
  private readonly CODE_EXPIRE_TIME = 300; // 验证码有效期5分钟
  private readonly LIMIT_TIME = 300; // 限制时间5分钟
  private readonly MAX_SEND_COUNT = 10; // 最大发送次数
  private readonly DEVICE_COUNT_PREFIX = 'device_sms_count:';
  private readonly LAST_SEND_PREFIX = 'device_sms_time:';
  private readonly DEVICE_LIMIT_TIME = 300; // 设备限制时间5分钟
  private readonly DEVICE_MAX_SEND_COUNT = 10; // 设备最大发送次数
  private userRepository: Repository<User>;
  private dictionaryRepository: Repository<Dictionary>;
  private readonly USER_TOKEN_PREFIX = 'user_token:';
  private readonly TOKEN_EXPIRE_TIME = 24 * 60 * 60; // token有效期1天
  private readonly JWT_SECRET = config.auth.JWT_SECRET;  

  constructor() {   
    this.wxSDK = createWxSDK(config.mpWeixin);
    this.smsSDK = createSmsSDK(config.sms);
    this.redis = new RedisService();
    this.userRepository = AppDataSource.getRepository(User);
    this.dictionaryRepository = AppDataSource.getRepository(Dictionary);
  }

  /**
   * 生成验证码
   */
  private generateCode(): string {
    return Math.random().toString().slice(-6);
  }

  /**
   * 发送验证码
   */
  async sendVerifyCode(phone: string, deviceId: string): Promise<any> {
    // 检查设备发送次数限制
    const deviceKey = `${this.DEVICE_COUNT_PREFIX}${deviceId}`;
    const deviceCount = await this.redis.get(deviceKey);
    
    if (deviceCount && parseInt(deviceCount) >= this.DEVICE_MAX_SEND_COUNT) {
      throw new Error('该设备发送次数过多，请稍后再试');
    }

    // 检查发送次数限制
    const countKey = `${this.SEND_COUNT_PREFIX}${phone}`;
    const count = await this.redis.get(countKey);
    
    if (count && parseInt(count) >= this.MAX_SEND_COUNT) {
      throw new Error('发送次数过多，请稍后再试');
    }
    //检查1分钟内发送次数，1分钟只能发送一条
    // 检查1分钟内发送次数限制
    const lastSendKey = `${this.LAST_SEND_PREFIX}${phone}`;
    const lastSendTime = await this.redis.get(lastSendKey);

    if (lastSendTime) {
      const currentTime = Math.floor(Date.now() / 1000); // 当前时间戳（秒）
      const lastTime = parseInt(lastSendTime);
      const timeDiff = currentTime - lastTime;

      if (timeDiff < 60) {
        throw new Error('1分钟内只能发送一条验证码，请稍后再试');
      }
    }

    // 生成验证码
    const code = this.generateCode();
    const codeKey = `${this.VERIFY_CODE_PREFIX}${phone}`;

    try {
      // 发送短信
      await this.smsSDK.sendSms({
        phoneNumbers: phone,
        signName: SMS_TEMPLATE.VERIFY_CODE.SIGN,
        templateCode: SMS_TEMPLATE.VERIFY_CODE.CODE,
        templateParam: SMS_TEMPLATE.VERIFY_CODE.PARAMS(code)
      });

      // 存储验证码
      await this.redis.setex(codeKey, this.CODE_EXPIRE_TIME, code);

      // 更新发送次数
      const newCount = count ? parseInt(count) + 1 : 1;
      await this.redis.setex(countKey, this.LIMIT_TIME, newCount.toString());

      // 更新设备发送次数
      const newDeviceCount = deviceCount ? parseInt(deviceCount) + 1 : 1;
      await this.redis.setex(deviceKey, this.DEVICE_LIMIT_TIME, newDeviceCount.toString());

      // 更新最近发送时间
      const currentTime = Math.floor(Date.now() / 1000); // 当前时间戳（秒）
      await this.redis.setex(lastSendKey, 60, currentTime.toString()); // 设置1分钟过期

      return code;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 验证验证码
   */
  async verifyCode(phone: string, code: string): Promise<boolean> {
    const codeKey = `${this.VERIFY_CODE_PREFIX}${phone}`;
    const savedCode = await this.redis.get(codeKey);

    if (!savedCode) {
      throw new Error('验证码已过期');
    }

    if (savedCode !== code) {
      throw new Error('验证码错误');
    }

    // 验证成功后删除验证码
    await this.redis.del(codeKey);
    return true;
  }

  /**
   * 登录并返回设备标识
   */
  async login(code: string) {
    try {
      const wxResponse = await this.wxSDK.login.code2Session(code);
      
      // 查询是否存在用户
      const existingUser = await this.userRepository.findOne({
        where: { wxOpenid: wxResponse.openid }
      });

      // 如果用户存在，生成token并保存到redis
      if (existingUser) {
        const token = this.generateToken(existingUser);
        
        // 存储用户信息到Redis
        const userKey = `${this.USER_TOKEN_PREFIX}${existingUser.id}`;
        await this.redis.setex(
          userKey,
          this.TOKEN_EXPIRE_TIME,
          JSON.stringify(existingUser)
        );

        return {
          ...wxResponse,
          deviceId: wxResponse.openid,
          isRegistered: true,
          ...existingUser,
          token
        };
      }

      // 用户不存在，返回微信登录信息
      return {
        ...wxResponse,
        deviceId: wxResponse.openid,
        isRegistered: false
      };
    } catch (error) {
      throw error;
    }
  }

  async decryptPhoneNumber(sessionKey: string, encryptedData: string, iv: string) {
    try {
      // 使用SDK解密手机号
      const phoneInfo = this.wxSDK.login.decryptPhoneNumber(
        sessionKey,
        encryptedData,
        iv
      );
      return phoneInfo;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 注册用户并生成token
   */
  async register(params: RegisterParams): Promise<{ user: User; token: string }> {
    // 1. 验证验证码
    const isValidCode = await this.verifyCode(params.mobile, params.verifyCode);
    if (!isValidCode) {
      throw new Error('验证码错误或已过期');
    }

    // 2. 验证身份证是否已被使用
    const existingUserByIdCard = await this.userRepository.findOne({
      where: { idCard: params.idCard }
    });
    if (existingUserByIdCard) {
      throw new Error('该身份证已被注册');
    }

    // 3. 验证手机号是否已被使用
    const existingUser = await this.userRepository.findOne({
      where: { mobile: params.mobile }
    });
    if (existingUser) {
      throw new Error('该手机号已被注册');
    }

    try {
      // 验证日期格式
      const birthdayRegex = /^\d{4}-\d{2}-\d{2}$/;
      if (!birthdayRegex.test(params.birthday)) {
        throw new Error('出生日期格式不正确，应为YYYY-MM-DD');
      }

      // 4. 生成用户ID
      const userId = this.generateUserId();

      // 5. 创建新用户
      const user = new User({
        id: userId,
        name: params.name,
        gender: params.gender,
        idCard: params.idCard,
        mobile: params.mobile,
        address: params.address,
        permanentAddress: params.permanentAddress,
        idCardFrontPhoto: params.idCardFrontPhoto,
        avatar: params.avatar,
        nickname: params.nickname,
        wxOpenid: params.openId,
        status: UserStatus.NORMAL
      });

      // 保存用户
      const savedUser = await this.userRepository.save(user);

      // 生成JWT token
      const token = this.generateToken(savedUser);

      // 存储用户信息到Redis
      const userKey = `${this.USER_TOKEN_PREFIX}${savedUser.id}`;
      await this.redis.setex(
        userKey,
        this.TOKEN_EXPIRE_TIME,
        JSON.stringify({
          id: savedUser.id,
          name: savedUser.name,
          mobile: savedUser.mobile,
          avatar: savedUser.avatar,
          nickname: savedUser.nickname,
          status: savedUser.status
        })
      );

      // 删除验证码
      const codeKey = `${this.VERIFY_CODE_PREFIX}${params.mobile}`;
      await this.redis.del(codeKey);

      return {
        user: savedUser,
        token
      };
    } catch (error: Error | unknown) {
      const message = error instanceof Error ? error.message : 'Unknown error';
      throw new Error(`注册失败: ${message}`);
    }
  }

  /**
   * 生成用户ID
   */
  private generateUserId(): string {
    // 生成格式为 TN_随机值12位 的用户ID
    const randomPart = Math.random().toString(36).substring(2, 14).toUpperCase();
    return `TN_${randomPart}`;
  }

  /**
   * 从Redis获取用户信息
   */
  async getUserFromCache(userId: string): Promise<any | null> {
    const userKey = `${this.USER_TOKEN_PREFIX}${userId}`;
    const userJson = await this.redis.get(userKey);
    return userJson ? JSON.parse(userJson) : null;
  }

  /**
   * 更新Redis中的用户信息
   */
  async updateUserCache(userId: string, userData: any): Promise<void> {
    const userKey = `${this.USER_TOKEN_PREFIX}${userId}`;
    await this.redis.setex(
      userKey,
      this.TOKEN_EXPIRE_TIME,
      JSON.stringify(userData)
    );
  }

  private generateToken(user: User): string {
    return jwt.sign(
      {
        id: user.id,
        name: user.name,
        mobile: user.mobile
      },
      this.JWT_SECRET,
      { expiresIn: '24h' }
    );
  }
  /**
   * 更新用户 token 并获取最新用户信息
   */
  async refreshToken(userId: string): Promise<{ user: any; token: string }> {
    try {
      // 获取最新的用户信息
      const user = await this.userRepository.findOne({
        where: { id: userId }
      });

      if (!user) {
        throw new Error('用户不存在');
      }

      // 生成新的 token
      const token = this.generateToken(user);

      // 更新 Redis 中的用户信息
      const userKey = `${this.USER_TOKEN_PREFIX}${user.id}`;
      await this.redis.setex(
        userKey,
        this.TOKEN_EXPIRE_TIME,
        JSON.stringify({
          id: user.id,
          name: user.name,
          mobile: user.mobile,
          avatar: user.avatar,
          nickname: user.nickname,
          status: user.status
        })
      );

      return {
        user: {
          id: user.id,
          name: user.name,
          mobile: user.mobile,
          avatar: user.avatar,
          nickname: user.nickname,
          status: user.status,
          wxOpenid: user.wxOpenid
        },
        token
      };
    } catch (error) {
      console.error('refreshToken error:', error);
      throw new Error('更新 token 失败');
    }
  }

  /**
   * 自动注册用户（简化版，跳过验证码验证）
   * 用于微信登录时自动创建用户
   */
  async autoRegister(params: Partial<RegisterParams>): Promise<{ user: User; token: string }> {
    try {
      // 生成用户ID
      const userId = this.generateUserId();

      // 创建新用户，只使用微信提供的基本信息
      const user = new User({
        id: userId,
        name: params.name || '微信用户',
        gender: params.gender || Gender.MALE,
        nickname: params.nickname || '',
        avatar: params.avatar || '',
        wxOpenid: params.openId || '',
        // 其他字段设置为默认值或留空，等用户后续补充
        idCard: params.idCard || '',
        mobile: params.mobile || '',
        address: params.address || '', // 确保 address 有默认值
        permanentAddress: params.permanentAddress || '', // 确保 permanentAddress 有默认值
        status: UserStatus.NORMAL
      });

      // 保存用户
      const savedUser = await this.userRepository.save(user);

      // 生成JWT token
      const token = this.generateToken(savedUser);

      // 存储用户信息到Redis
      const userKey = `${this.USER_TOKEN_PREFIX}${savedUser.id}`;
      await this.redis.setex(
        userKey,
        this.TOKEN_EXPIRE_TIME,
        JSON.stringify(savedUser)
      );

      return {
        user: savedUser,
        token
      };
    } catch (error: Error | unknown) {
      const message = error instanceof Error ? error.message : 'Unknown error';
      throw new Error(`自动注册失败: ${message}`);
    }
  }

  /**
   * 更新用户信息
   * 用于用户后续补充个人信息
   */
  async updateUserInfo(userId: string, updateData: Partial<User>): Promise<User> {
    try {
      // 查找用户
      const user = await this.userRepository.findOne({
        where: { id: userId }
      });

      if (!user) {
        throw new Error('用户不存在');
      }

      // 更新用户信息
      Object.assign(user, updateData);
      
      // 保存更新后的用户信息
      const updatedUser = await this.userRepository.save(user);

      // 更新Redis中的用户信息
      const userKey = `${this.USER_TOKEN_PREFIX}${user.id}`;
      await this.redis.setex(
        userKey,
        this.TOKEN_EXPIRE_TIME,
        JSON.stringify({
          id: updatedUser.id,
          name: updatedUser.name,
          mobile: updatedUser.mobile,
          avatar: updatedUser.avatar,
          nickname: updatedUser.nickname,
          status: updatedUser.status
        })
      );

      return updatedUser;
    } catch (error: Error | unknown) {
      const message = error instanceof Error ? error.message : 'Unknown error';
      throw new Error(`更新用户信息失败: ${message}`);
    }
  }
}